package com.cy.pj.sys.service.aspect;

import com.cy.pj.common.ShiroUtils;
import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.util.IPUtils;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Aspect 切面类型
 */
@Slf4j
@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private SysLogService sysLogService;

    //@Pointcut("bean(sysUserServiceImpl)")
    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object around(ProceedingJoinPoint jp) throws Throwable{
        try{
            long start = System.currentTimeMillis();
            log.info("start:{}", start);
            Object result = jp.proceed();
            long end = System.currentTimeMillis();
            log.info("end:{}", end);
            // 保存用户的正常行为日志(谁在什么时间，执行了什么操作，访问了什么方法，传递的参数)
            // ProceedingJoinPoint + 反射
            saveUserLog(jp, end - start);
            return result;
        } catch (Throwable e) {
            log.error("after:{}", e.getMessage());
            throw e;
        }
    }

    // 思路：从下往上
    private void saveUserLog(ProceedingJoinPoint pjp, long time) throws Exception {
        // 1、获取用户行为日志
        //String ip = InetAddress.getLocalHost().getHostAddress();// ip
        String ip = IPUtils.getIpAddr();// ip
        String username = ShiroUtils.getUserName();// 用户名
        MethodSignature ms = (MethodSignature)pjp.getSignature();
        String name = ms.getName();
        Class[] parameterTypes = ms.getParameterTypes();

        Class<?> targetClass = pjp.getTarget().getClass();
        Method targetMethod = targetClass.getDeclaredMethod(name, parameterTypes);
        RequiredLog requiredLog = targetMethod.getDeclaredAnnotation(RequiredLog.class);
        String operation = requiredLog.operation();// 操作
        String method = targetClass.getName() + "." + targetMethod.getName();// 方法全限定名
        String params = new ObjectMapper().writeValueAsString(pjp.getArgs());// 方法参数列表
        // 2、封装用户行为日志
        SysLog entity = new SysLog();
        entity.setIp(ip);
        entity.setUsername(username);
        entity.setOperation(operation);
        entity.setMethod(method);
        entity.setParams(params);
        entity.setTime(time);
        // 3、将日志写入数据库
        /*
         * 线程对象的创建既耗时，又占用内存
         */
        //new Thread(){
        //    @Override
        //    public void run() {
        //        sysLogService.saveObject(entity);
        //    }
        //}.start();
        sysLogService.saveObject(entity);
    }
}
